package org.breathe.server.handler;

import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.breathe.aof.AofManager;
import org.breathe.command.Command;
import org.breathe.command.CommandType;
import org.breathe.datastruct.RedisBytes;
import org.breathe.protocal.Resp;
import org.breathe.protocal.decode.BulkString;
import org.breathe.protocal.decode.Errors;
import org.breathe.protocal.decode.RespArray;
import org.breathe.server.core.RedisCore;

/**
 * @author: breathe
 * @createTime: 2025-05-12
 */
@Slf4j
@Getter
@Sharable
public class RespCommandHandler extends SimpleChannelInboundHandler<Resp> {
    private final RedisCore redisCore;
    private final AofManager aofManager;
    public RespCommandHandler(RedisCore redisCore, AofManager aofManager) {
        this.redisCore = redisCore;
        this.aofManager = aofManager;
    }
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Resp resp) throws Exception {
        if (resp instanceof RespArray respArray) {
            Resp response = processCommand(respArray);
            if (response != null) {
                channelHandlerContext.channel().writeAndFlush(response);
            }
        } else {
            channelHandlerContext.channel().writeAndFlush(new Errors("Don't support command"));
        }
    }
    private Resp processCommand(RespArray respArray) {
        if (respArray.getContent().length == 0) {
            return new Errors("Command can't become null");
        }
        try {
            Resp[] array = respArray.getContent();
            RedisBytes cmd = ((BulkString) array[0]).getContent();
            String commandName = cmd.getString().toUpperCase();
            CommandType commandType = null;
            try {
                commandType = CommandType.valueOf(commandName);
            } catch (IllegalArgumentException e) {
                return new Errors("don't have this command");
            }
            Command command = commandType.getSupplier().apply(redisCore);
            command.setContext(array);

            Resp result = command.handle();
            if (aofManager != null && command.writeCommand()) {
                aofManager.append(respArray);
            }
            return result;
        } catch (Exception e) {
            log.error("command run fail", e);
            return new Errors("command run fail");
        }
    }
}